/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package coalescent.is.nb.jobs;

import coalescent.is.cef.command.listener.exe.VizSamplers_EC;
import commons.core.Duration;
import commons.nb.jobs.properties.*;

import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static coalescent.is.cef.command.listener.exe.VizSamplers_Multi_EC.*;
import static commons.nb.jobs.CommonsJobPropertys.BOOLEAN_EXE_JOB_PROPERTY;

/**
 * @since
 * @version
 * @author Susanta Tewari
 * @history Created on 4/4/13.
 */
public class Props_IS {

    private static final PropertySet SAMPLERS_SET = new PropertySetImpl("samplers", "Samplers",
                                                        "Samplers");

    public static Property[] allSamplers(String prefix) {

        return new Property[] { addSampler_gt_EGT(prefix), addSampler_gt_SD(prefix),
                                addSampler_gt_HUW(prefix) };
    }

    public static Property[] color(String prefix, boolean addExact) {

        List<Property> list = new ArrayList<>();

        if (addExact) list.add(addExactColor(prefix));

        Collections.addAll(list, addSamplerColor_gt_EGT(prefix), addSamplerColor_gt_SD(prefix),
                           addSamplerColor_gt_HUW(prefix));

        return list.toArray(new Property[0]);
    }

    /**
     * @param prefix
     * @param dummy_theta {@code true} if the UI should include a field for {@code theta};
     * {@code false} otherwise
     * @return combo property for supplying {@code KC64Data}
     */
    public static ComboProperty IterationStrategies(String prefix) {


        // dependent props: size_prop, k69data-builder prop
        final Property size_prop = IS_SAMPLE_SIZE_PROP(prefix);
        final Property time_prop = IS_DURATION_PROP(prefix);


        // controller prop
        final Property<String> controller_prop =
            Propertys.ofString("IterationStrategies-controller", "Iteration Strategy",
                               "Choose iteration strategy either based on time or sample size",
                               PropertySets.PARAMS, prefix + ".itrType", "sampleSize");

        time_prop.setActive(false);
        controller_prop.setPropEditorClass(PropertyEditors_IS.IterationStrategiesPE.class);
        controller_prop.addDependent(size_prop);
        controller_prop.addDependent(time_prop);
        controller_prop.setPropertyChangeListenerDelegate(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {

                final String value = controller_prop.getValue();

                switch (value) {

                    case "sampleSize" :
                        size_prop.setActive(true);
                        time_prop.setActive(false);

                        break;

                    case "time" :
                        size_prop.setActive(false);
                        time_prop.setActive(true);

                        break;

                    default :
                        throw new IllegalStateException();
                }
            }

        });


        // prepare combo
        final ComboPropertyImpl combo_prop = new ComboPropertyImpl(controller_prop, size_prop);

        combo_prop.addProperty(time_prop);

        return combo_prop;
    }

    public static Property<Integer> IS_SAMPLE_SIZE_PROP(final String prefix) {

        final Property<Integer> propImpl = Propertys.ofInteger();


        // descriptions & display category
        propImpl.setName("is-sample-size");
        propImpl.setDisplayName("IS Sample Size");
        propImpl.setShortDescription("Number of runs for the importance sampling");
        propImpl.setPropertySet(PropertySets.PARAMS);
        propImpl.setKey(prefix + ".itrTypeVal");
        propImpl.setValue(100);

        return propImpl;
    }

    public static Property<Duration> IS_DURATION_PROP(final String prefix) {

        return Propertys.ofDuration( //J-
                "is-duration","IS Run Duration",
                "IS Run Duration. Valid values of the format: 1h 25m 10s; 25m etc.",
                PropertySets.PARAMS,
                prefix + ".itrTypeVal",
                new Duration("1m"));//J+

    }

    private static Property<Boolean> addSampler_gt_EGT(final String prefix) {

        final Property<Boolean> prop = Propertys.ofBoolean();

        prop.setName("sampler-gt-EGT");
        prop.setDisplayName("gt-EGT");
        prop.setShortDescription("Etheir-Griffiths-Tavare Sampler for Gene-Tree");
        prop.setPropertySet(SAMPLERS_SET);
        prop.setKey(prefix + ".gt_EGT");
        prop.setValue(true);

        return prop;
    }

    private static Property<Color> addExactColor(final String prefix) {

        return Propertys.ofColor("exactProb-color", "Color for Exact Probability",
                                 "Choose a color for marking exact probability",
                                 PropertySets.MARKERS, prefix + ".exactProb-Color",
                                 new Color(230, 203, 159));
    }

    private static Property<Color> addSamplerColor_gt_EGT(final String prefix) {

        return Propertys.ofColor("samplerColor-egt", "Color for EGT",
                                 "Choose a color for sampler EGT", PropertySets.MARKERS,
                                 prefix + ".gt_EGT-Color", new Color(230, 161, 171));
    }

    private static Property<Color> addSamplerColor_gt_SD(final String prefix) {

        return Propertys.ofColor("samplerColor-SD", "Color for SD",
                                 "Choose a color for sampler SD", PropertySets.MARKERS,
                                 prefix + ".gt_SD-Color", new Color(134, 230, 134));
    }

    private static Property<Color> addSamplerColor_gt_HUW(final String prefix) {

        return Propertys.ofColor("samplerColor-HUW", "Color for HUW",
                                 "Choose a color for sampler HUW", PropertySets.MARKERS,
                                 prefix + ".gt_HUW-Color", new Color(171, 216, 230));
    }

    private static Property<Boolean> addSampler_gt_SD(final String prefix) {

        final Property<Boolean> prop = Propertys.ofBoolean();

        prop.setName("sampler-gt-SD");
        prop.setDisplayName("gt-SD");
        prop.setShortDescription("Stephens-Donnelly Sampler for Gene-Tree");
        prop.setPropertySet(SAMPLERS_SET);
        prop.setKey(prefix + ".gt_SD");
        prop.setValue(true);

        return prop;
    }

    private static Property<Boolean> addSampler_gt_HUW(final String prefix) {

        final Property<Boolean> prop = Propertys.ofBoolean();

        prop.setName("sampler-gt-Hobolth");
        prop.setDisplayName("gt-Hobolth");
        prop.setShortDescription("Hobolth Sampler for Gene-Tree");
        prop.setPropertySet(SAMPLERS_SET);
        prop.setKey(prefix + ".gt_HUW");
        prop.setValue(true);

        return prop;
    }

    private Props_IS() {}

    /**
     * Execution trackers for mean, SE and ESS.
     */
    public static class TRACKERS {

        private TRACKERS() {}

        public static JobProperty[] all() {

            return new JobProperty[] {
                BOOLEAN_EXE_JOB_PROPERTY(new VizSamplers_EC.IS_TRACKER_MEAN(), MEAN()),    // mean
                BOOLEAN_EXE_JOB_PROPERTY(new VizSamplers_EC.IS_TRACKER_SE(), SE()),    // se
                BOOLEAN_EXE_JOB_PROPERTY(new VizSamplers_EC.IS_TRACKER_ESS(), ESS()) };    // ess
        }

        public static JobProperty[] allMulti() {

            return new JobProperty[] {

                BOOLEAN_EXE_JOB_PROPERTY(new IS_TRACKER_MEAN(), MEAN()),    // mean
                BOOLEAN_EXE_JOB_PROPERTY(new IS_TRACKER_SE(), SE()),    // se
                BOOLEAN_EXE_JOB_PROPERTY(new IS_TRACKER_ESS(), ESS())    // ess
            };
        }

        private static Property<Boolean> MEAN() {

            final Property<Boolean> prop = Propertys.ofBoolean();

            prop.setName("is-tracker-mean");
            prop.setDisplayName("Mean");
            prop.setShortDescription(
                "Tracks Mean over Iterations along with Exact (if, available)");
            prop.setPropertySet(PropertySets.TRACKERS);
            prop.setValue(true);

            return prop;
        }

        private static Property<Boolean> SE() {

            final Property<Boolean> prop = Propertys.ofBoolean();

            prop.setName("is-tracker-SE");
            prop.setDisplayName("SE");
            prop.setShortDescription("Tracks Standard Error over Iterations");
            prop.setPropertySet(PropertySets.TRACKERS);
            prop.setValue(false);

            return prop;
        }

        private static Property<Boolean> ESS() {

            final Property<Boolean> prop = Propertys.ofBoolean();

            prop.setName("is-tracker-ESS");
            prop.setDisplayName("ESS");
            prop.setShortDescription("Tracks Effective Sample Size (ESS) over Iterations");
            prop.setPropertySet(PropertySets.TRACKERS);
            prop.setValue(false);

            return prop;
        }
    }
}
